package edt;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.TimeZone;

import javax.swing.JOptionPane;

import com.google.gdata.client.GoogleService.InvalidCredentialsException;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.extensions.When;
import com.google.gdata.data.extensions.Where;
import com.google.gdata.util.ServiceException;
import com.thirdnf.ResourceScheduler.Appointment;

/**
 * 
 * @author Nicolas Proust
 *
 */
public class SyncListener implements ActionListener {

	// The base URL for a user's calendar metafeed.
	private static final String METAFEED_URL_BASE = "https://www.google.com/calendar/feeds/";
	// The string to add to the user's metafeedUrl to access the event feed for
	// their primary calendar.
	private static final String EVENT_FEED_URL_SUFFIX = "/private/full";	
	// The URL for the metafeed of the specified user.
	private static URL metafeedUrl = null;
	// The URL for the event feed of the specified user's primary calendar.
	private static URL eventFeedUrl = null;
	
	MySchedulerModel model;
	MyScheduler scheduler;
	
	public SyncListener(MyScheduler myScheduler, MySchedulerModel model) {
		this.scheduler=myScheduler;
		this.model = model;
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		
		CalendarService myService = new CalendarService("edt");
		
		String userName = scheduler.login.getText();
		String userPassword = scheduler.pass.getText();
		
		
		InetAddress Ip = null;
		try {
			Ip = InetAddress.getLocalHost();
		} catch (UnknownHostException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	    
	    Properties prop = new Properties();
	    FileInputStream in = null;
		try {
			in = new FileInputStream("proxy.properties");
			prop.load(in); 
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		String host = prop.getProperty("host"); 
		String port = prop.getProperty("port"); 
	    
	    if(host!=null && port!=null) {
	    	System.setProperty("https.proxyHost", host);
	    	System.setProperty("https.proxyPort", port);
	    }
		
		try {
		metafeedUrl = new URL(METAFEED_URL_BASE + userName);
		eventFeedUrl = new URL(METAFEED_URL_BASE + userName
		+ EVENT_FEED_URL_SUFFIX);
		} catch (MalformedURLException e) {
		      // Bad URL
		      System.err.println("Mauvais URL.");
		      e.printStackTrace();
		      return;
		    }
		
		try {
			myService.setUserCredentials(userName, userPassword);
		
			// Suppression des creneaux
			Iterator<Appointment> itrDel = model.getCreneauToDelete().iterator();
			
			while(itrDel.hasNext()) {
				CreneauModele appointement = (CreneauModele) itrDel.next();
				List<CalendarEventEntry> toDelete = new ArrayList<CalendarEventEntry>();
					
				CalendarEventFeed resultFeed = myService.getFeed(eventFeedUrl,
						CalendarEventFeed.class);
				
				for (int i = 0; i < resultFeed.getEntries().size(); i++) {
					CalendarEventEntry entry = resultFeed.getEntries().get(i);
					SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH");
					Calendar calendar = new GregorianCalendar();
					//Date de l'objet entry
					DateTime time = entry.getTimes().get(0).getStartTime();
					Date date = new Date(time.getValue());
					String dateStr = format.format(date);
					//Date de l'objet appointment
					calendar.set(Calendar.DAY_OF_WEEK, convertStringDayToInt(appointement.getResource().getTitle()));
					org.joda.time.DateTime time2 = appointement.getDateTime();
					calendar.set(Calendar.HOUR_OF_DAY, time2.getHourOfDay());
					Date date2 = calendar.getTime();
					String dateStr2 = format.format(date2);
					
					if (appointement.getTitle().equalsIgnoreCase(entry.getTitle().getPlainText())
						&& dateStr.equals(dateStr2)) {
						toDelete.add(entry);
					}
				}
				
				deleteEvents(myService,toDelete);
				
				System.out.println("Successfully deleted event");
			}

			// Ajout des creneaux
			Iterator<Appointment> itrAdd = model.getAllCreneau().iterator();
			
			while(itrAdd.hasNext()) {
				CreneauModele appointement = (CreneauModele) itrAdd.next();
					
				CalendarEventFeed resultFeed = myService.getFeed(eventFeedUrl,
						CalendarEventFeed.class);
				boolean exist = false;
				for (int i = 0; i < resultFeed.getEntries().size(); i++) {
					
					CalendarEventEntry entry = resultFeed.getEntries().get(i);
					SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH");
					
					Date date1 = new Date(entry.getTimes().get(0).getStartTime().getValue());
					String dateStr = format.format(date1);
					
					Calendar calendar = new GregorianCalendar();
					calendar.set(Calendar.DAY_OF_WEEK, convertStringDayToInt(appointement.getResource().getTitle()));
					org.joda.time.DateTime time2 = appointement.getDateTime();
					calendar.set(Calendar.HOUR_OF_DAY, time2.getHourOfDay());
					Date date2 = calendar.getTime();
					String dateStr2 = format.format(date2);
					
					if ((appointement.getTitle().equalsIgnoreCase(entry.getTitle().getPlainText())
						&& dateStr.equals(dateStr2)) || dateStr.equals(dateStr2)) {
						exist = true;
					}
				}
				
				if (!exist) {
					CalendarEventEntry singleEvent = createEvent(myService,appointement);
						
					System.out.println("Successfully created event "
						+ singleEvent.getTitle().getPlainText());
					
					appointement.setAlreadySync(true);
				}
			}
			
			
		} catch (InvalidCredentialsException e) {
	        System.out.println("Mauvais id ou mdp");
			JOptionPane.showMessageDialog(scheduler, "Mauvais identifiant ou mot de passe", "Erreur",
			        JOptionPane.ERROR_MESSAGE);		
	    } catch (IOException e) {
	        // Communications error
	        System.err.println("There was a problem communicating with the service.");
	        e.printStackTrace();
	    } catch (ServiceException e) {
	        // Server side error
	        System.err.println("The server had a problem handling your request.");
	        e.printStackTrace();
	    }
	}

	/*
	 * Traitement de sync vers google
	 */
	/**
	 * 
	 * @param service
	 * @param eventTitle
	 * @param eventContent
	 * @param duree
	 * @param heuredebut
	 * @return
	 * @throws ServiceException
	 * @throws IOException
	 */
	private static CalendarEventEntry createEvent(CalendarService service,
		String eventTitle, String eventContent, int duree, int heuredebut, String jour) 
		throws ServiceException, IOException {
		  
	    CalendarEventEntry myEntry = new CalendarEventEntry();

	    myEntry.setTitle(new PlainTextConstruct(eventTitle));
	    myEntry.setContent(new PlainTextConstruct("test"));

	    // Heure de d�but
	    Calendar calendar = new GregorianCalendar();
	    calendar.set(Calendar.DAY_OF_WEEK, convertStringDayToInt(jour));
	    Date date = calendar.getTime();
	    //int javaDay = convertDay(calendar.get(Calendar.DAY_OF_WEEK));

	    date.setHours(heuredebut);
	    date.setMinutes(0);
	    calendar.setTime(date);
	    DateTime startTime = new DateTime(calendar.getTime(), TimeZone.getDefault());

	    // Heure de fin en fonction de la dur�e
	    calendar.add(Calendar.MINUTE, duree);
	    DateTime endTime = new DateTime(calendar.getTime(), 
	    TimeZone.getDefault());

	    When eventTimes = new When();
	    eventTimes.setStartTime(startTime);
	    eventTimes.setEndTime(endTime);
	    myEntry.addTime(eventTimes);

	    // Send the request and receive the response:
	    return service.insert(eventFeedUrl, myEntry);
	}
	
	private static CalendarEventEntry createEvent(CalendarService service,
		CreneauModele appointment) 
		throws ServiceException, IOException {
		  
		String titre = appointment.getTitle();
		String content = "Type:" + appointment.getType() + "," +
						"Groupe:" + appointment.getGroupe();
		int duree = (int)(appointment.getDuration().getStandardSeconds())/60;
		int heuredebut = appointment.getDateTime().getHourOfDay();
		String jour = appointment.getResource().getTitle();
		String location = appointment.getClasse();
		
	    CalendarEventEntry myEntry = new CalendarEventEntry();
	    myEntry.setTitle(new PlainTextConstruct(titre));
	    myEntry.setContent(new PlainTextConstruct(content));
	    Where lieu = new Where();
	    lieu.setValueString(location);
	    myEntry.addLocation(lieu);
	    // Heure de d�but
	    Calendar calendar = new GregorianCalendar();
	    calendar.set(Calendar.DAY_OF_WEEK, convertStringDayToInt(jour));
	    Date date = calendar.getTime();
	    //int javaDay = convertDay(calendar.get(Calendar.DAY_OF_WEEK));
	    date.setHours(heuredebut);
	    date.setMinutes(0);
	    calendar.setTime(date);
	    DateTime startTime = new DateTime(calendar.getTime(), TimeZone.getDefault());
	    // Heure de fin en fonction de la dur�e
	    calendar.add(Calendar.MINUTE, duree);
	    DateTime endTime = new DateTime(calendar.getTime(), 
	    TimeZone.getDefault());

	    When eventTimes = new When();
	    eventTimes.setStartTime(startTime);
	    eventTimes.setEndTime(endTime);
	    myEntry.addTime(eventTimes);

	    // Send the request and receive the response:
	    return service.insert(eventFeedUrl, myEntry);
	}
	
	private static void deleteEvents(CalendarService service,
		List<CalendarEventEntry> eventsToDelete) throws ServiceException,
		IOException {

		// Add each item in eventsToDelete to the batch request.
		CalendarEventFeed batchRequest = new CalendarEventFeed();
		for (int i = 0; i < eventsToDelete.size(); i++) {
			CalendarEventEntry toDelete = eventsToDelete.get(i);
			// Modify the entry toDelete with batch ID and operation type.
			BatchUtils.setBatchId(toDelete, String.valueOf(i));
			BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);
			batchRequest.getEntries().add(toDelete);
		}
		
		// Get the URL to make batch requests to
		CalendarEventFeed feed = service.getFeed(eventFeedUrl,
			CalendarEventFeed.class);
		Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
		URL batchUrl = new URL(batchLink.getHref());
		
		// Submit the batch request
		CalendarEventFeed batchResponse = service.batch(batchUrl, batchRequest);
	}
	
	/**
	 * 
	 * @param jour
	 * @return
	 */
	public static int convertStringDayToInt(String jour) {
		int day = 0;
		if (jour.equalsIgnoreCase("Lundi")) {
			day = 2;
		} else if (jour.equalsIgnoreCase("Mardi")) {
			day = 3;
		} else if (jour.equalsIgnoreCase("Mercredi")) {
			day = 4;
		} else if (jour.equalsIgnoreCase("Jeudi")) {
			day = 5;
		} else if (jour.equalsIgnoreCase("Vendredi")) {
			day = 6;
		} else if (jour.equalsIgnoreCase("Samedi")) {
			day = 7;
		} else if (jour.equalsIgnoreCase("Dimanche")) {
			day = 1;
		}
		return day; 
	}
	
	public static List<CalendarEventEntry> getExistant(CalendarService service, 
		CreneauModele appointement) {
		
		List<CalendarEventEntry> exist = new ArrayList<CalendarEventEntry>();
		
		CalendarEventFeed resultFeed = null;
		try {
			resultFeed = service.getFeed(eventFeedUrl,
					CalendarEventFeed.class);
			
			for (int i = 0; i < resultFeed.getEntries().size(); i++) {
				CalendarEventEntry entry = resultFeed.getEntries().get(i);
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-hh");
				Calendar calendar = new GregorianCalendar();
				//Date de l'objet entry
				DateTime time = entry.getTimes().get(0).getStartTime();
				Date date = new Date(time.getValue());
				String dateStr = format.format(date);
				//Date de l'objet appointment
				calendar.set(Calendar.DAY_OF_WEEK, convertStringDayToInt(appointement.getResource().getTitle()));
				Date date2 = calendar.getTime();
				String dateStr2 = format.format(date2);
				
				if (appointement.getTitle().equalsIgnoreCase(entry.getTitle().getPlainText())
						&& dateStr.equals(dateStr2)) {
					exist.add(entry);
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return exist;
	}

}
